#!/usr/bin/env python
# ftp://ftp.tummy.com/pub/tummy/Python/jlock.py
#
#  Generic locking routines

revision = "$Revision: 1.1.1.1 $"
rcsid = "$Id: jlock.py,v 1.1.1.1 2000/03/01 21:31:48 jafo Exp $"

import time
import os
import string

LockError = 'Lock Error'

class lock:
	def __init__(self, name, retries = None, tryBreak = 1, doRaise = 0,
			sleepTime = 1.3):
		self.lockedByPid = None
		self.pid = str(os.getpid())
		self.lockFile = name
		self.lockFile2 = self.lockFile + '.' + self.pid

		self.haveLock = 0
		while not self.haveLock:
			#  break a lock for a non-existant pid
			if tryBreak and os.path.exists(self.lockFile):
				try:
					self.lockedByPid = string.strip(open(self.lockFile,
							'r').readline())
				except IOError: continue
				try: os.kill(int(self.lockedByPid), 0)
				except OSError:
					try:
						os.unlink(self.lockFile)
						os.unlink(self.lockFile + '.' + self.lockedByPid)
					except OSError: pass

			#  try to obtain the lock
			try:
				#  write our PID to our lock-file
				fp = open(self.lockFile2, 'w')
				fp.write('%s\n' % self.pid)
				fp.close()

				os.link(self.lockFile2, self.lockFile)
				self.haveLock = 1
			except OSError:
				if retries == None or retries > 0: time.sleep(sleepTime)

			#  exit if we aren't supposed to wait
			if retries != None:
				if retries < 1: break
				retries = retries - 1

		if not self.haveLock:
			os.unlink(self.lockFile2)
			if doRaise: raise(LockError, "Unable to obtain lock")
	
	def release(self):
		import os


		try:
			if os.path.exists(self.lockFile2): os.unlink(self.lockFile2)
			if self.haveLock and os.path.exists(self.lockFile):
				os.unlink(self.lockFile)
			self.haveLock = 0
		except OSError: pass

	def __del__(self):
		self.release()

############
#  run tests
if __name__ == '__main__':
	lock = lock('test', retries = 10, tryBreak = 0, doRaise = 1)
	lock.haveLock
